"""Utility functions for security checks."""

import re

from jwt import DecodeError, ExpiredSignatureError
from werkzeug.security import check_password_hash
import jwt
from datetime import datetime, timedelta, timezone

import dbhelper

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'}
MAX_FILE_SIZE = 10 * 1024 * 1024
SECRET_KEY: (str | None) = None


def get_secret():
    """
    Update the secret key from the database for later use.
    """
    global SECRET_KEY
    SECRET_KEY = dbhelper.get_token("secret")


def check_username(username: str) -> bool:
    """
    Checks if the given username is valid.
    A valid username can only contain alphanumeric characters,
    """
    if re.match(r'^[a-zA-Z0-9_]+$', username):
        return True
    return False


def verify_password(username: str, password: str) -> bool:
    """
    Checks if the given password matches the given username.
    """
    try:
        user = dbhelper.get_user(username)
        return check_password_hash(user[2], password)
    except RuntimeError:
        return False


def generate_jwt(username: str) -> str:
    """
    Generate a JWT token for an existing user, expiring in 6 hours.

    :param username: the specified username
    :return: the generated JWT token
    """
    if SECRET_KEY is None:
        get_secret()

    payload = {
        'username': username,
        'exp': datetime.now(timezone.utc) + timedelta(hours=6)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm='HS256')


def verify_jwt(token: str) -> (str | None):
    """
    Verify a give JWT token.

    :param token: the given JWT token
    :return: the decoded username, or `None` if the token is invalid
    """
    if SECRET_KEY is None:
        get_secret()

    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return payload['username']
    except DecodeError or KeyError or ExpiredSignatureError:
        return None
